﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
using System.Reflection;
using System.IO;
using System.Text;
using System.ComponentModel;

namespace CookstaFramework.Objects
{
    /// <summary>
    /// Description of RecordCollection.
    /// </summary>
    [Serializable]
    public sealed class RecordCollection<T> : CollectionBase, IDisposable, IEnumerable<T> where T : RecordBase
    {
        private List<T> _records;
        [XmlIgnore]
        public bool Disposed { get; set; }
        [XmlIgnore]
        public new int Count { get { return this._records.Count; } }
        public T this[int index] { get { return this._records[index]; } }

        public RecordCollection()
        {
            this._records = new List<T>();
        }
        
        ~RecordCollection()
        {
        	Dispose(true);
        }

        public RecordCollection(List<T> records)
        {
            this._records = records;
        }

        public void Add(List<T> records)
        {
            this._records.AddRange(records);
        }

        public new IEnumerator<T> GetEnumerator()
        {
            foreach (T record in this._records)
                yield return record;
        }

        public void Add(T item)
        {
            this._records.Add(item);
        }

        public void Remove(T item)
        {
            this._records.Remove(item);
        }

        public List<T> ToList()
        {
            return this._records;
        }

        public BindingList<T> ToBindingList()
        {
            return new BindingList<T>(this._records);
        }

        public T Find(Predicate<T> match)
        {
            return this._records.Find(match);
        }

        public List<T> FindAll(Predicate<T> match)
        {
            return this._records.FindAll(match);
        }

        public void Sort(Comparison<T> comparison)
        {
            this._records.Sort(comparison);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            this.Disposed = disposing;
        }

        public string GetXML()
        {
            using (StringWriter sw = new StringWriter())
            {
                new XmlSerializer(typeof(List<T>)).Serialize(sw, this._records);
                return sw.ToString();
            }
        }

        public void FillFromXML(string xml)
        {
            this._records = (List<T>)new XmlSerializer(typeof(List<T>)).Deserialize(new StringReader(xml));
        }

        public string GetCSV()
        {
            string results = "";
            string theSeperator = "";
            PropertyInfo[] pi = typeof(T).GetProperties();

            foreach (PropertyInfo p in pi)
            {
                results += theSeperator + p.Name;
                theSeperator = ",";
            }
            theSeperator = "";

            foreach (T item in this._records)
            {
                results += "\n";
                foreach (PropertyInfo p in pi)
                {
                    results += theSeperator + p.GetValue(item,null).ToString();
                    theSeperator = ",";
                }
                theSeperator = "";
            }
            return results;
        }

        public void FillFromCSV(string csv)
        {
            StringReader sr = new StringReader(csv);
            List<PropertyInfo> properties = new List<PropertyInfo>(typeof(T).GetProperties());
            List<string> propertyNames = new List<string>(sr.ReadLine().Split(','));
            string current = "";
            string[] currentValues;
            RecordCollection<T> records = new RecordCollection<T>();
            T temp = null;

            while (true)
            {
                current = sr.ReadLine();
                if (current == "" || current == null)
                    break;
                else
                {
                    currentValues = current.Split(',');
                    for (int i = 0; i < currentValues.Length; i++)
                    {
                        PropertyInfo p =
                        properties.Find(delegate(PropertyInfo pi)
                            {
                                return pi.Name == propertyNames[i];
                            });
                        p.SetValue(temp, Convert.ChangeType(currentValues[i], p.PropertyType), null);
                    }
                    records.Add(temp);
                }
            }
        }
    }
}
